package com.example.zhu29.bledemo.util;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextPaint;
import android.util.DisplayMetrics;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.AbsListView;
import android.widget.GridView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;

/**
 * Created by Administrator on 2017/12/12.
 */

public class ViewUtil {

    /**
     * The base width of the UI design.
     */
    public static int UI_WIDTH = 720;

    /**
     * The base height of the UI design.
     */
    public static int UI_HEIGHT = 1280;
    /**
     * The density of the UI design.
     */
    public static int UI_DENSITY = 2;

    /**
     * Invalid value
     */
    public static final int INVALID = Integer.MIN_VALUE;

    /**
  * Description: Reset the height of the AbsListView. The outermost layout of the item is used.
   * RelativeLayout, if the calculation is not accurate, specify a height for the RelativeLayout
  *
  * @param absListView the abs list view
   * @param lineNumber A few rows per row ListView one line an item
   * @param verticalSpace the vertical space
  */
    public static void setAbsListViewHeight(AbsListView absListView,
                                            int lineNumber, int verticalSpace) {

        int totalHeight = getAbsListViewHeight(absListView, lineNumber,
                verticalSpace);
        ViewGroup.LayoutParams params = absListView.getLayoutParams();
        params.height = totalHeight;
        ((ViewGroup.MarginLayoutParams) params).setMargins(0, 0, 0, 0);
        absListView.setLayoutParams(params);
    }

    /**
   * Description: Get the height of the AbsListView.
   *
   * @param absListView the abs list view
   * @param lineNumber A few rows per row ListView one line an item
   * @param verticalSpace the vertical space
   * @return the abs list view height
   */
    public static int getAbsListViewHeight(AbsListView absListView,
                                           int lineNumber, int verticalSpace) {
        int totalHeight = 0;
        int w = View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED);
        int h = View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED);
        absListView.measure(w, h);
        ListAdapter mListAdapter = absListView.getAdapter();
        if (mListAdapter == null) {
            return totalHeight;
        }

        int count = mListAdapter.getCount();
        if (absListView instanceof ListView) {
            for (int i = 0; i < count; i++) {
                View listItem = mListAdapter.getView(i, null, absListView);
                listItem.measure(w, h);
                totalHeight += listItem.getMeasuredHeight();
            }
            if (count == 0) {
                totalHeight = verticalSpace;
            } else {
                totalHeight = totalHeight
                        + (((ListView) absListView).getDividerHeight() * (count - 1));
            }

        } else if (absListView instanceof GridView) {
            int remain = count % lineNumber;
            if (remain > 0) {
                remain = 1;
            }
            if (mListAdapter.getCount() == 0) {
                totalHeight = verticalSpace;
            } else {
                View listItem = mListAdapter.getView(0, null, absListView);
                listItem.measure(w, h);
                int line = count / lineNumber + remain;
                totalHeight = line * listItem.getMeasuredHeight() + (line - 1)
                        * verticalSpace;
            }

        }
        return totalHeight;

    }

    /**
   * Measure this view
   * Finally get the width and height by getMeasuredWidth().
   *
   * @param view view to be measured
   * @return Measured view
   */
    public static void measureView(View view) {
        ViewGroup.LayoutParams p = view.getLayoutParams();
        if (p == null) {
            p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
        }

        int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
        int lpHeight = p.height;
        int childHeightSpec;
        if (lpHeight > 0) {
            childHeightSpec = View.MeasureSpec.makeMeasureSpec(lpHeight,
                    View.MeasureSpec.EXACTLY);
        } else {
            childHeightSpec = View.MeasureSpec.makeMeasureSpec(0,
                    View.MeasureSpec.UNSPECIFIED);
        }
        view.measure(childWidthSpec, childHeightSpec);
    }

    /**
      * Get the width of this View
      * Measure this view and finally get the width by getMeasuredWidth().
      *
      * @param view view to be measured
      * @return Measured width of view
      */
    public static int getViewWidth(View view) {
        measureView(view);
        return view.getMeasuredWidth();
    }

    /**
     * Get the height of this View
    * Measure this view and finally get the height via getMeasuredHeight().
     *
     * @param view view to be measured
     * @return measured height of view
     */
    public static int getViewHeight(View view) {
        measureView(view);
        return view.getMeasuredHeight();
    }

    /**
     * Get screen width pixels
     *
     * @param context
     * @return
     */
    public static int getScreenWidth(Context context) {
        DisplayMetrics dm = DisplayUtil.getDisplayMetrics(context);
        return dm.widthPixels;
    }

    /**
     * Get screen height pixels
     *
     * @param context
     * @return
     */
    public static int getScreenHeight(Context context) {
        DisplayMetrics dm = DisplayUtil.getDisplayMetrics(context);
        return dm.heightPixels;
    }

    /**
     * Get screen width DPI
     *
     * @param context
     * @return
     */
    public static float getScreenWidthDpi(Context context) {
        DisplayMetrics dm = DisplayUtil.getDisplayMetrics(context);
        return dm.xdpi;
    }

    /**
     * Get screen height DPI
     *
     * @param context
     * @return
     */
    public static float getScreenHeightDpi(Context context) {
        DisplayMetrics dm = DisplayUtil.getDisplayMetrics(context);
        return dm.ydpi;
    }

    /**
     * Get screen density (pixel ratio: 0.75/1.0/1.5/2.0)
     *
     * @param context
     * @return
     */
    public static float getScreenDensity(Context context) {
        DisplayMetrics dm = DisplayUtil.getDisplayMetrics(context);
        return dm.density;
    }

    /**
     * Get screen density (pixels per inch: 120/160/240/320)
     *
     * @param context
     * @return
     */
    public static int getScreenDensityDpi(Context context) {
        DisplayMetrics dm = DisplayUtil.getDisplayMetrics(context);
        return dm.densityDpi;
    }

    /**
     * Remove yourself from the father layout
     *
     * @param v
     */
    public static void removeSelfFromParent(View v) {
        ViewParent parent = v.getParent();
        if (parent != null) {
            if (parent instanceof ViewGroup) {
                ((ViewGroup) parent).removeView(v);
            }
        }
    }


    /**
     * Description: dip is converted to px.
     *
     * @param context  the context
     * @param dipValue the dip value
     * @return px value
     */
    public static float dip2px(Context context, float dipValue) {
        DisplayMetrics mDisplayMetrics = DisplayUtil.getDisplayMetrics(context);
        return applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, mDisplayMetrics);
    }

    /**
     * Description: px is converted to dip.
     *
     * @param context the context
     * @param pxValue the px value
     * @return dip value
     */
    public static float px2dip(Context context, float pxValue) {
        DisplayMetrics mDisplayMetrics = DisplayUtil.getDisplayMetrics(context);
        return pxValue / mDisplayMetrics.density;
    }

    /**
     * Description: sp is converted to px.
     *
     * @param context the context
     * @param spValue the sp value
     * @return sp value
     */
    public static float sp2px(Context context, float spValue) {
        DisplayMetrics mDisplayMetrics = DisplayUtil.getDisplayMetrics(context);
        return applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, mDisplayMetrics);
    }

    /**
     * Description: px is converted to sp.
     *
     * @param context the context
     * @param pxValue the sp value
     * @return sp value
     */
    public static float px2sp(Context context, float pxValue) {
        DisplayMetrics mDisplayMetrics = DisplayUtil.getDisplayMetrics(context);
        return pxValue / mDisplayMetrics.scaledDensity;
    }

    /**
     * Description: Scale according to screen size.
     *
     * @param context the context
     * @param value   the px value
     * @return the int
     */
    public static int scaleValue(Context context, float value) {
        DisplayMetrics mDisplayMetrics = DisplayUtil.getDisplayMetrics(context);
        //In order to be compatible with small size and large density
        if (mDisplayMetrics.scaledDensity > UI_DENSITY) {
            //density
            if (mDisplayMetrics.widthPixels > UI_WIDTH) {
                value = value * (1.3f - 1.0f / mDisplayMetrics.scaledDensity);
            } else if (mDisplayMetrics.widthPixels < UI_WIDTH) {
                value = value * (1.0f - 1.0f / mDisplayMetrics.scaledDensity);
            }
        }
        return scale(mDisplayMetrics.widthPixels,
                mDisplayMetrics.heightPixels, value);
    }

    /**
     * Description: Scales the text according to the screen size.
     *
     * @param context the context
     * @param value   the px value
     * @return the int
     */
    public static int scaleTextValue(Context context, float value) {
        DisplayMetrics mDisplayMetrics = DisplayUtil.getDisplayMetrics(context);
        //In order to be compatible with small size and large density
        if (mDisplayMetrics.scaledDensity > 2) {
            //Zoom out to one of the density points
            value = value * (1.1f - 1.0f / mDisplayMetrics.scaledDensity);
        }
        return scale(mDisplayMetrics.widthPixels,
                mDisplayMetrics.heightPixels, value);
    }

    /**
     * Description: Scale according to screen size.
     *
     * @param displayWidth  the display width
     * @param displayHeight the display height
     * @param pxValue       the px value
     * @return the int
     */
    public static int scale(int displayWidth, int displayHeight, float pxValue) {
        if (pxValue == 0) {
            return 0;
        }
        float scale = 1;
        try {
            float scaleWidth = (float) displayWidth / UI_WIDTH;
            float scaleHeight = (float) displayHeight / UI_HEIGHT;
            scale = Math.min(scaleWidth, scaleHeight);
        } catch (Exception e) {
        }
        return Math.round(pxValue * scale + 0.5f);
    }


    /**
     * The algorithm in the official source code of TypedValue, convert any unit into PX unit
     *
     * @param unit TypedValue.COMPLEX_UNIT_DIP
     * @param value The value of the corresponding unit
     * @param metrics density
     * @return px value
     */
    public static float applyDimension(int unit, float value,
                                       DisplayMetrics metrics) {
        switch (unit) {
            case TypedValue.COMPLEX_UNIT_PX:
                return value;
            case TypedValue.COMPLEX_UNIT_DIP:
                return value * metrics.density;
            case TypedValue.COMPLEX_UNIT_SP:
                return value * metrics.scaledDensity;
            case TypedValue.COMPLEX_UNIT_PT:
                return value * metrics.xdpi * (1.0f / 72);
            case TypedValue.COMPLEX_UNIT_IN:
                return value * metrics.xdpi;
            case TypedValue.COMPLEX_UNIT_MM:
                return value * metrics.xdpi * (1.0f / 25.4f);
        }
        return 0;
    }


    /**
     * Description: The View tree is recursively called for adaptation.
     * AbAppConfig.uiWidth = 1080;
     * AbAppConfig.uiHeight = 700;
     * scaleContentView((RelativeLayout)findViewById(R.id.rootLayout));
     * Requires the units in the layout to use px and the size of the artwork, including all width and height, Padding, Margin, text size
     *
     * @param contentView
     */
    public static void scaleContentView(ViewGroup contentView) {
        ViewUtil.scaleView(contentView);
        if (contentView.getChildCount() > 0) {
            for (int i = 0; i < contentView.getChildCount(); i++) {
                View view = contentView.getChildAt(i);
                if (view instanceof ViewGroup) {
                    scaleContentView((ViewGroup) (view));
                } else {
                    scaleView(contentView.getChildAt(i));
                }
            }
        }
    }

    /**
     * Description: The View tree is recursively called for adaptation.
     * AbAppConfig.uiWidth = 1080;
     * AbAppConfig.uiHeight = 700;
     * scaleContentView(context,R.id.rootLayout);
     * Requires the units in the layout to use px and the size of the artwork, including all width and height, Padding, Margin, text size
     *
     * @param parent
     * @param id
     */
    public static void scaleContentView(View parent, int id) {
        ViewGroup contentView = null;
        View view = parent.findViewById(id);
        if (view instanceof ViewGroup) {
            contentView = (ViewGroup) view;
            scaleContentView(contentView);
        }
    }

    /**
     * Description: The View tree is recursively called for adaptation.
     * AbAppConfig.uiWidth = 1080;
     * AbAppConfig.uiHeight = 700;
     * scaleContentView(context,R.id.rootLayout);
     * Requires the units in the layout to use px and the size of the artwork, including all width and height, Padding, Margin, text size
     *
     * @param context
     * @param id
     */
    public static void scaleContentView(Context context, int id) {
        ViewGroup contentView = null;
        View view = ((Activity) context).findViewById(id);
        if (view instanceof ViewGroup) {
            contentView = (ViewGroup) view;
            scaleContentView(contentView);
        }
    }

    /**
     * Scale the View proportionally to the dimensions in the layout
     *
     * @param view
     */
    @SuppressLint("NewApi")
    public static void scaleView(View view) {
        if (view instanceof TextView) {
            TextView textView = (TextView) view;
            setTextSize(textView, textView.getTextSize());
        }

        ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) view.getLayoutParams();
        if (null != params) {
            int width = INVALID;
            int height = INVALID;
            if (params.width != ViewGroup.LayoutParams.WRAP_CONTENT
                    && params.width != ViewGroup.LayoutParams.MATCH_PARENT) {
                width = params.width;
            }

            if (params.height != ViewGroup.LayoutParams.WRAP_CONTENT
                    && params.height != ViewGroup.LayoutParams.MATCH_PARENT) {
                height = params.height;
            }

            //size
            setViewSize(view, width, height);

            // Padding
            setPadding(view, view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), view
                    .getPaddingBottom());
        }

        // Margin
        if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
            ViewGroup.MarginLayoutParams mMarginLayoutParams = (ViewGroup.MarginLayoutParams) view
                    .getLayoutParams();
            if (mMarginLayoutParams != null) {
                setMargin(view, mMarginLayoutParams.leftMargin, mMarginLayoutParams.topMargin, mMarginLayoutParams
                        .rightMargin, mMarginLayoutParams.bottomMargin);
            }
        }

        if (Build.VERSION.SDK_INT >= 16) {
            //Maximum and minimum width
            int minWidth = scaleValue(view.getContext(), view.getMinimumWidth());
            int minHeight = scaleValue(view.getContext(), view.getMinimumHeight());
            view.setMinimumWidth(minWidth);
            view.setMinimumHeight(minHeight);
        }
    }

    /**
     * Scale text size
     *
     * @param textView button
     * @param size     sp value
     * @return
     */
    public static void setSPTextSize(TextView textView, float size) {
        float scaledSize = scaleTextValue(textView.getContext(), size);
        textView.setTextSize(scaledSize);
    }

    /**
     * The size of the text is scaled so that the advantage of the setting is that the size of the text is not related to the density.
     * Ability to display text sizes correctly on different screens
     *
     * @param textView   button
     * @param sizePixels px value
     * @return
     */
    public static void setTextSize(TextView textView, float sizePixels) {
        float scaledSize = scaleTextValue(textView.getContext(), sizePixels);
        textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, scaledSize);
    }

    /**
     *Scale text size
     *
     * @param context
     * @param textPaint
     * @param sizePixels px value
     * @return
     */
    public static void setTextSize(Context context, TextPaint textPaint, float sizePixels) {
        float scaledSize = scaleTextValue(context, sizePixels);
        textPaint.setTextSize(scaledSize);
    }

    /**
     * Scale text size
     *
     * @param context
     * @param paint
     * @param sizePixels px value
     * @return
     */
    public static void setTextSize(Context context, Paint paint, float sizePixels) {
        float scaledSize = scaleTextValue(context, sizePixels);
        paint.setTextSize(scaledSize);
    }

    /**
     * Set the PX size of the View
     *
     * @param view        If the code is new, the View needs to set a suitable LayoutParams.
     * @param widthPixels
     * @param heightPixels
     */
    public static void setViewSize(View view, int widthPixels, int heightPixels) {
        int scaledWidth = scaleValue(view.getContext(), widthPixels);
        int scaledHeight = scaleValue(view.getContext(), heightPixels);
        ViewGroup.LayoutParams params = view.getLayoutParams();
        if (params == null) {
            // AbLogUtil.e (ViewUtil.class, "setViewSize error, if it is the new view of the code, you need to set a suitable LayoutParams");
            return;
        }
        if (widthPixels != INVALID) {
            params.width = scaledWidth;
        }
        if (heightPixels != INVALID) {
            params.height = scaledHeight;
        }
        view.setLayoutParams(params);
    }

    /**
     * SettingPX padding.
     *
     * @param view   the view
     * @param left   the left padding in pixels
     * @param top    the top padding in pixels
     * @param right  the right padding in pixels
     * @param bottom the bottom padding in pixels
     */
    public static void setPadding(View view, int left,
                                  int top, int right, int bottom) {
        int scaledLeft = scaleValue(view.getContext(), left);
        int scaledTop = scaleValue(view.getContext(), top);
        int scaledRight = scaleValue(view.getContext(), right);
        int scaledBottom = scaleValue(view.getContext(), bottom);
        view.setPadding(scaledLeft, scaledTop, scaledRight, scaledBottom);
    }

    /**
     * Setting PX margin.
     *
     * @param view   the view
     * @param left   the left margin in pixels
     * @param top    the top margin in pixels
     * @param right  the right margin in pixels
     * @param bottom the bottom margin in pixels
     */
    public static void setMargin(View view, int left, int top,
                                 int right, int bottom) {
        int scaledLeft = scaleValue(view.getContext(), left);
        int scaledTop = scaleValue(view.getContext(), top);
        int scaledRight = scaleValue(view.getContext(), right);
        int scaledBottom = scaleValue(view.getContext(), bottom);

        if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
            ViewGroup.MarginLayoutParams mMarginLayoutParams = (ViewGroup.MarginLayoutParams) view
                    .getLayoutParams();
            if (mMarginLayoutParams != null) {
                if (left != INVALID) {
                    mMarginLayoutParams.leftMargin = scaledLeft;
                }
                if (right != INVALID) {
                    mMarginLayoutParams.rightMargin = scaledRight;
                }
                if (top != INVALID) {
                    mMarginLayoutParams.topMargin = scaledTop;
                }
                if (bottom != INVALID) {
                    mMarginLayoutParams.bottomMargin = scaledBottom;
                }
                view.setLayoutParams(mMarginLayoutParams);
            }
        }

    }

    /**
     * Modify the height of the ordinary View<br>
     * Use caution in the Adapter---getView method
     */
    public static void changeH(View v, int H) {
        ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) v.getLayoutParams();
        params.height = H;
        v.setLayoutParams(params);
    }

    /**
           * Modify the width of the ordinary View<br>
           * Use caution in the Adapter---getView method
           */
    public static void changeW(View v, int W) {
        ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) v.getLayoutParams();
        params.width = W;
        v.setLayoutParams(params);
    }

    /**
           * Modify the width and height of the control<br>
           * Use caution in the Adapter---getView method
           *
           * @param v control
           * @param W width
           * @param H height
           */
    public static void changeWH(View v, int W, int H) {
        ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) v.getLayoutParams();
        params.width = W;
        params.height = H;
        v.setLayoutParams(params);
    }

    /**
   * <p>Description: Set the height of the listview</p>
   *
   * @param listView
   * @param itemHeight height of the item
   */
    public static void setListViewHeightBasedOnChildren(ListView listView, int itemHeight) {
        //Get the listview adapter
        ListAdapter listAdapter = listView.getAdapter();
        if (listAdapter == null) {
            return;
        }

        int totalHeight = 0;

        for (int i = 0; i < listAdapter.getCount(); i++) {
            View listItem = listAdapter.getView(i, null, listView);
            listItem.measure(0, 0);
            totalHeight += listItem.getMeasuredHeight();
        }

        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight;
        listView.setLayoutParams(params);
    }

    /**
     * Convert layout to View
     *
     * @param context
     * @param layoutId
     * @return
     */
    public static View layoutToView(Context context, int layoutId) {
        LayoutInflater inflater = LayoutInflater.from(context);
        View v = inflater.inflate(layoutId, null);
        return v;
    }

    /**
     * Convert Drawable to Bitmap
     *
     * @param drawable
     * @return
     */
    public static Bitmap drawableToBitmap(Drawable drawable) {
        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
                drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
        drawable.draw(canvas);
        return bitmap;
    }

    @SuppressWarnings("unchecked")
    public static <T extends View> T get(View view, int id) {
        SparseArray<View> viewHolder = (SparseArray<View>) view.getTag();

        if (viewHolder == null) {
            viewHolder = new SparseArray<View>();
            view.setTag(viewHolder);
        }
        View childView = viewHolder.get(id);
        if (childView == null) {
            childView = view.findViewById(id);
            viewHolder.put(id, childView);
        }
        return (T) childView;
    }

}
